home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.5 Complementary Applications 2004 February / SGI IRIX 6.5 Complementary Applications 2004 February.iso / dist / cde.idb / usr / dt / share / examples / template / template.c.z / template.c
Encoding:
C/C++ Source or Header  |  2003-11-18  |  29.3 KB  |  1,145 lines

  1. /*
  2.  * template.c
  3.  *
  4.  * Copyright 2000, Silicon Graphics, Inc.
  5.  * ALL RIGHTS RESERVED
  6.  * 
  7.  * UNPUBLISHED -- Rights reserved under the copyright laws of the United
  8.  * States.   Use of a copyright notice is precautionary only and does not
  9.  * imply publication or disclosure.
  10.  *
  11.  * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
  12.  * Use, duplication or disclosure by the Government is subject to restrictions
  13.  * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
  14.  * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
  15.  * in similar or successor clauses in the FAR, or the DOD or NASA FAR
  16.  * Supplement.  Contractor/manufacturer is Silicon Graphics, Inc.,
  17.  * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
  18.  *
  19.  * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
  20.  * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
  21.  * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
  22.  * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
  23.  * GRAPHICS, INC.
  24.  */
  25. /* $XConsortium: template.c /main/cde1_maint/2 1995/09/06 02:06:59 lehors $ */
  26. /*
  27.  * (c) Copyright 1993, 1994 Hewlett-Packard Company    
  28.  * (c) Copyright 1993, 1994 International Business Machines Corp.
  29.  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  30.  * (c) Copyright 1993, 1994 Novell, Inc.
  31.  */
  32.  
  33.  
  34. /*
  35.  * template.c
  36.  *
  37.  * Example code for typical Dt application
  38.  *
  39.  * Simple spray-can drawing tool
  40.  */
  41.  
  42. #include <X11/IntrinsicP.h>
  43. #include <X11/CoreP.h>
  44. #include <nl_types.h>
  45. #include <Xm/XmAll.h>
  46. #include <Dt/Dnd.h>
  47. #include <Dt/Dts.h>
  48. #include <Dt/HelpDialog.h>
  49. #include <Tt/tttk.h>
  50.  
  51. /* default brush - used when the brush bitmap file is not found at run-time. */
  52. #include "default_brush.bm"
  53.  
  54. /* Portability for catopen */
  55. #if !defined(NL_CAT_LOCALE)
  56. #define NL_CAT_LOCALE 0
  57. #endif
  58.  
  59.  
  60. #define ApplicationClass "Template"
  61. #define MessageCatalog "template.cat"
  62. #define HelpVolume "template"
  63. #define HelpTopic "_hometopic"
  64. #define IconPixmap "template_icon.pm"
  65. #define IconMask "template_icon_m.bm"
  66. #define Suffix ".template"
  67. #define SuffixLength 9
  68. #define UnnamedFile "unnamed.template"
  69. #define SearchPattern "*.template"
  70. #define DataType "TemplateData"
  71. #define ToolTalkPType "DT_Example_Template"
  72. #define FileSignature "@template@\n"
  73.  
  74. #define MallocInc 10
  75.  
  76. typedef struct _WindowData {
  77.     int            npoints;
  78.     int            nalloc;
  79.     XPoint        *points;
  80.     Widget        shell;
  81.     Widget        openDialog;
  82.     Widget        saveDialog;
  83.     char        *name;        /* NULL if no file */
  84.     struct _WindowData    *next;
  85. } WindowData;
  86.  
  87. static XtAppContext appContext;
  88. static nl_catd msgCatalog;
  89. static Widget appShell;
  90. static WindowData *windowList = NULL;
  91. static XContext wdContext;
  92. static Atom WM_DELETE_WINDOW;
  93. static Atom WM_SAVE_YOURSELF;
  94. static char *appnameString;
  95. static char *separatorString;
  96. static char *untitledString;
  97. static char *argv0;
  98. static char *programName;
  99.  
  100. /* ToolTalk stuff */
  101. static int ttfd;
  102. static char *procid;
  103. static Tt_pattern *ttpat;
  104. static Tt_status ttrc;
  105. static Tt_message HandleTtMedia(Tt_message, void *, Tttk_op, Tt_status,
  106.     unsigned char *, int, char *, char *);
  107.  
  108. #define DrawingTranslations "#replace\
  109.     <Btn1Down>: DrawingAreaInput()\n\
  110.     <Btn1Motion>: DrawingAreaInput()"
  111.  
  112. static void ClearCb(Widget, XtPointer, XtPointer);
  113. static void HelpCb(Widget, XtPointer, XtPointer);
  114. static void NewCb(Widget, XtPointer, XtPointer);
  115. static void OpenCb(Widget, XtPointer, XtPointer);
  116. static void OpenOkCb(Widget, XtPointer, XtPointer);
  117. static void SaveCb(Widget, XtPointer, XtPointer);
  118. static void SaveOkCb(Widget, XtPointer, XtPointer);
  119. static void PrintCb(Widget, XtPointer, XtPointer);
  120. static void ExitCb(Widget, XtPointer, XtPointer);
  121. static void ExposeCb(Widget, XtPointer, XtPointer);
  122. static void InputCb(Widget, XtPointer, XtPointer);
  123. static void DropTransferCb(Widget, XtPointer, XtPointer);
  124. static void SaveSessionCb(Widget, XtPointer, XtPointer);
  125.  
  126. typedef enum {
  127.     LOAD_EMPTY, LOAD_FILE, LOAD_BUFFER
  128. } LoadType;
  129.  
  130. static void Fatal(char*);
  131. static void ReallyExit(int);
  132. static void SetTitle(Widget,char*);
  133. static Boolean NewWindow(LoadType,char*,int);
  134. static WindowData *NewData(void);
  135. static void AssocData(WindowData*,Widget);
  136. static WindowData *FindData(Widget);
  137. static void DestroyData(WindowData*);
  138. static Boolean LoadFile(WindowData*,char*);
  139. static Boolean LoadBuffer(WindowData*,void*,int);
  140. static void FreeData(WindowData*);
  141. static void PrintData(WindowData*);
  142. static void AddPoint(WindowData*, int, int);
  143. static void DrawPoint(Widget, int, int);
  144. static char* AppendString(char*,char*);
  145.  
  146. static XtCallbackRec DropTransferCbList[] = {
  147.     { DropTransferCb, NULL},
  148.     { NULL, NULL}
  149. };
  150.  
  151. static XrmOptionDescRec optionTable[] = {
  152.     {"-print",    ".printMode",   XrmoptionIsArg, NULL},
  153.     {"-server",   ".serverMode",  XrmoptionIsArg, NULL},
  154. };
  155.  
  156. typedef struct {
  157.     String printMode;
  158.     String serverMode;
  159. } appResourceRec;
  160.  
  161. static XtResource appResources[] = {
  162.     { "printMode", "PrintMode", XtRString, sizeof(String),
  163.     XtOffsetOf(appResourceRec, printMode), XtRString, NULL },
  164.     { "serverMode", "ServerMode", XtRString, sizeof(String),
  165.     XtOffsetOf(appResourceRec, serverMode), XtRString, NULL },
  166. };
  167.  
  168. main(int argc, char **argv)
  169. {
  170.     int i;
  171.     appResourceRec argvals;
  172.  
  173.     argv0 = argv[0];
  174.     programName = strrchr(argv[0], '/');
  175.     if (programName == NULL)
  176.     programName = argv[0];
  177.     else
  178.     ++programName;
  179.  
  180.     XtSetLanguageProc(NULL, NULL, NULL);
  181.  
  182.     msgCatalog = catopen(MessageCatalog, NL_CAT_LOCALE);
  183.  
  184.     appShell = XtAppInitialize(&appContext, ApplicationClass,
  185.                    optionTable, XtNumber(optionTable),
  186.                    &argc, argv, NULL, NULL, 0);
  187.  
  188.     XtGetApplicationResources(appShell, &argvals,
  189.                   appResources, XtNumber(appResources),
  190.                   NULL, 0);
  191.  
  192.     wdContext = XUniqueContext();
  193.  
  194.     WM_DELETE_WINDOW = XmInternAtom(XtDisplay(appShell), "WM_DELETE_WINDOW",
  195.                     False);
  196.     WM_SAVE_YOURSELF = XmInternAtom(XtDisplay(appShell), "WM_SAVE_YOURSELF",
  197.                     False);
  198.  
  199.     appnameString = catgets(msgCatalog, 1, 1, "Template");
  200.     separatorString = catgets(msgCatalog, 1, 5, " - ");
  201.     untitledString = catgets(msgCatalog, 1, 6, "(untitled)");
  202.  
  203.     if (argvals.printMode != NULL) {
  204.     /* Load up each file and print it, then exit */
  205.     WindowData *wd = NewData();
  206.     for (i = 1; i < argc; ++i) {
  207.         if (LoadFile(wd, argv[i]))
  208.         PrintData(wd);
  209.         else
  210.         fprintf(stderr,
  211.             catgets(msgCatalog, 1, 10, "template: can't open %s\n"),
  212.             argv[i]);
  213.     }
  214.     DestroyData(wd);
  215.     exit(0);
  216.     }
  217.  
  218.     /* Initialize Data Typing and ToolTalk */
  219.  
  220.     DtDtsLoadDataTypes();
  221.  
  222.     procid = ttdt_open(&ttfd, appnameString, "CDE", "1.0", True);
  223.     if (tt_ptr_error(procid) != TT_OK) {
  224.     Fatal(catgets(msgCatalog, 1, 7, "ttdt_open failed"));
  225.     }
  226.  
  227.     ttrc = ttmedia_ptype_declare(ToolTalkPType, 0, HandleTtMedia,
  228.                  NULL, True);
  229.     if (tt_is_err(ttrc)) {
  230.     Fatal(catgets(msgCatalog, 1, 8, "ttmedia_ptype_declare failed"));
  231.     }
  232.  
  233.     ttpat = ttdt_session_join(NULL, NULL, NULL, NULL, True);
  234.     if (tt_ptr_error(ttpat) != TT_OK) {
  235.     Fatal(catgets(msgCatalog, 1, 9, "ttdt_session_join failed"));
  236.     }
  237.  
  238.     XtAppAddInput(appContext, ttfd, (XtPointer)XtInputReadMask,
  239.           tttk_Xt_input_handler, NULL);
  240.  
  241.     if (argvals.serverMode != NULL) {
  242.     /*
  243.      * We're in server mode.  Thus do nothing until requested to do so
  244.      * through ToolTalk.
  245.      */
  246.     } else if (argc < 2) {
  247.     /* No files given, so put up an untitled window. */
  248.     (void) NewWindow(LOAD_EMPTY, NULL, 0);
  249.     } else {
  250.     /* Load each file into its own window. */
  251.     for (i = 1; i < argc; ++i)
  252.         (void) NewWindow(LOAD_FILE, argv[i], 0);
  253.     }
  254.  
  255.     /*
  256.      * Start the GUI.  Note that we explicitly do not realize the appShell
  257.      * widget, since it is the unmapped parent of all of the top-level shells 
  258.      * we pop up.
  259.      */
  260.  
  261.     XtAppMainLoop(appContext);
  262.     ReallyExit(0);
  263. }
  264.  
  265.  
  266. /*
  267.  * Close ToolTalk and exit.
  268.  */
  269. static void ReallyExit(int rc)
  270. {
  271.     tt_close();
  272.     exit(rc);
  273. }
  274.  
  275.  
  276. /*
  277.  * Issue an error message and exit.
  278.  */
  279. static void Fatal(char *msg)
  280. {
  281.     fprintf(stderr, "%s: %s\n", programName, msg);
  282.     exit(1);
  283. }
  284.  
  285.  
  286. /*
  287.  * Create a new top-level window.  If loadtype is LOAD_EMPTY, name_or_buf and 
  288.  * len are ignored.  If loadtype is LOAD_FILE, name_or_buf should point to the 
  289.  * name of the file to load, and len is ignored.  If loadtype is LOAD_BUFFER,
  290.  * name_or_buf is a pointer to the data buffer and len is its length.
  291.  */
  292. static Boolean
  293. NewWindow(LoadType loadtype, char *name_or_buf, int len)
  294. {
  295.     Widget toplevel, mainWindow, menuBar, frame1, frame2,
  296.     drawingArea, pd, cb, pb;
  297.     char *title;
  298.     XmString labelString;
  299.     XtTranslations drawingTranslations;
  300.     Pixmap iconPixmap;
  301.     Pixmap iconMask;
  302.     Pixel fg, bg;
  303.     Arg args[20];
  304.     int n;
  305.     WindowData *wd;
  306.  
  307.     wd = NewData();
  308.  
  309.     n = 0;
  310.     toplevel = XtCreatePopupShell("foo", topLevelShellWidgetClass,
  311.         appShell, args, n);
  312.  
  313.     /* Create main window */
  314.  
  315.     n = 0;
  316.     mainWindow = XmCreateMainWindow(toplevel, "mainWindow", args, n);
  317.     XtManageChild(mainWindow);
  318.  
  319.     /* Set window manager title and icon */
  320.  
  321.     XtVaGetValues(mainWindow, XmNforeground, &fg, XmNbackground, &bg, NULL);
  322.     iconPixmap = XmGetPixmap(XtScreen(toplevel), IconPixmap, fg, bg);
  323.     iconMask = XmGetPixmapByDepth(XtScreen(toplevel), IconMask, 1, 0, 1);
  324.     XtVaSetValues(toplevel,
  325.         XmNiconName, appnameString,
  326.         XmNiconPixmap, iconPixmap,
  327.         XmNiconMask, iconMask,
  328.         NULL);
  329.  
  330.     /* Create the GUI */
  331.  
  332.     menuBar = XmCreateMenuBar(mainWindow, "menuBar", NULL, 0);
  333.     XtManageChild(menuBar);
  334.  
  335.     /* File menu */
  336.  
  337.     pd = XmCreatePulldownMenu(menuBar, "fileMenu", NULL, 0);
  338.  
  339.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 1, "File"));
  340.     n = 0;
  341.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  342.     XtSetArg(args[n], XmNmnemonic, 'F'); n++;
  343.     XtSetArg(args[n], XmNsubMenuId, pd); n++;
  344.     cb = XmCreateCascadeButton(menuBar, "fileCascade", args, n);
  345.     XtManageChild(cb);
  346.     XmStringFree(labelString);
  347.  
  348.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 9, "New..."));
  349.     n = 0;
  350.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  351.     XtSetArg(args[n], XmNmnemonic, 'N'); n++;
  352.     pb = XmCreatePushButton(pd, "newButton", args, n);
  353.     XtManageChild(pb);
  354.     XtAddCallback(pb, XmNactivateCallback, NewCb, NULL);
  355.     XmStringFree(labelString);
  356.  
  357.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 2, "Open..."));
  358.     n = 0;
  359.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  360.     XtSetArg(args[n], XmNmnemonic, 'O'); n++;
  361.     pb = XmCreatePushButton(pd, "openButton", args, n);
  362.     XtManageChild(pb);
  363.     XtAddCallback(pb, XmNactivateCallback, OpenCb, (XtPointer)wd);
  364.     XmStringFree(labelString);
  365.  
  366.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 3,
  367.                                 "Save As..."));
  368.     n = 0;
  369.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  370.     XtSetArg(args[n], XmNmnemonic, 'S'); n++;
  371.     pb = XmCreatePushButton(pd, "saveButton", args, n);
  372.     XtManageChild(pb);
  373.     XtAddCallback(pb, XmNactivateCallback, SaveCb, (XtPointer)wd);
  374.     XmStringFree(labelString);
  375.  
  376.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 4, "Print"));
  377.     n = 0;
  378.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  379.     XtSetArg(args[n], XmNmnemonic, 'P'); n++;
  380.     pb = XmCreatePushButton(pd, "printButton", args, n);
  381.     XtManageChild(pb);
  382.     XtAddCallback(pb, XmNactivateCallback, PrintCb, (XtPointer)wd);
  383.     XmStringFree(labelString);
  384.  
  385.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 5, "Clear"));
  386.     n = 0;
  387.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  388.     XtSetArg(args[n], XmNmnemonic, 'C'); n++;
  389.     pb = XmCreatePushButton(pd, "clearButton", args, n);
  390.     XtManageChild(pb);
  391.     XtAddCallback(pb, XmNactivateCallback, ClearCb, (XtPointer)wd);
  392.     XmStringFree(labelString);
  393.  
  394.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 6, "Exit"));
  395.     n = 0;
  396.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  397.     XtSetArg(args[n], XmNmnemonic, 'E'); n++;
  398.     pb = XmCreatePushButton(pd, "exitButton", args, n);
  399.     XtManageChild(pb);
  400.     XtAddCallback(pb, XmNactivateCallback, ExitCb, (XtPointer)wd);
  401.     XmStringFree(labelString);
  402.  
  403.     /* Help menu */
  404.  
  405.     pd = XmCreatePulldownMenu(menuBar, "helpMenu", NULL, 0);
  406.  
  407.     labelString = XmStringCreateLocalized(catgets(msgCatalog, 2, 7, "Help"));
  408.     n = 0;
  409.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  410.     XtSetArg(args[n], XmNmnemonic, 'H'); n++;
  411.     XtSetArg(args[n], XmNsubMenuId, pd); n++;
  412.     cb = XmCreateCascadeButton(menuBar, "helpCascade", args, n);
  413.     XtManageChild(cb);
  414.     XmStringFree(labelString);
  415.  
  416.     XtVaSetValues(menuBar, XmNmenuHelpWidget, cb, NULL);
  417.  
  418.     labelString = XmStringCreateLocalized(catgets(msgCatalog,2,8, "Overview..."));
  419.     n = 0;
  420.     XtSetArg(args[n], XmNlabelString, labelString); n++;
  421.     XtSetArg(args[n], XmNmnemonic, 'O'); n++;
  422.     pb = XmCreatePushButton(pd, "helpButton", args, n);
  423.     XtManageChild(pb);
  424.     XtAddCallback(pb, XmNactivateCallback, HelpCb, NULL);
  425.     XmStringFree(labelString);
  426.  
  427.     /* Drawing work area */
  428.  
  429.     n = 0;
  430.     XtSetArg(args[n], XmNshadowThickness, 0); n++;
  431.     XtSetArg(args[n], XmNmarginWidth, 20); n++;
  432.     XtSetArg(args[n], XmNmarginHeight, 20); n++;
  433.     frame1 = XmCreateFrame(mainWindow, "frame1", args, n);
  434.     XtManageChild(frame1);
  435.  
  436.     n = 0;
  437.     XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  438.     frame2 = XmCreateFrame(frame1, "frame2", args, n);
  439.     XtManageChild(frame2);
  440.  
  441.     drawingTranslations = XtParseTranslationTable(DrawingTranslations);
  442.  
  443.     n = 0;
  444.     XtSetArg(args[n], XmNunitType, Xm100TH_MILLIMETERS); n++;
  445.     XtSetArg(args[n], XmNwidth, 12000); n++;
  446.     XtSetArg(args[n], XmNheight, 12000); n++;
  447.     XtSetArg(args[n], XmNtranslations, drawingTranslations); n++;
  448.     drawingArea = XmCreateDrawingArea(frame2, "drawingArea", args, n);
  449.     XtManageChild(drawingArea);
  450.     XtAddCallback(drawingArea, XmNexposeCallback, ExposeCb, NULL);
  451.     XtAddCallback(drawingArea, XmNinputCallback, InputCb, NULL);
  452.  
  453.     DtDndDropRegister(drawingArea,
  454.               DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
  455.               XmDROP_COPY, DropTransferCbList, NULL, 0);
  456.  
  457.     XmAddWMProtocolCallback(toplevel, WM_DELETE_WINDOW, ExitCb, (XtPointer)wd);
  458.     XmAddWMProtocolCallback(toplevel, WM_SAVE_YOURSELF, SaveSessionCb,
  459.                 (XtPointer)NULL);
  460.  
  461.     XtRealizeWidget(toplevel);
  462.     XtPopup(toplevel, XtGrabNone);
  463.  
  464.     AssocData(wd, toplevel);
  465.  
  466.     switch (loadtype) {
  467.     case LOAD_EMPTY:
  468.     SetTitle(toplevel, NULL);
  469.     return True;
  470.     case LOAD_FILE:
  471.         return LoadFile(wd, name_or_buf);
  472.     case LOAD_BUFFER:
  473.     return LoadBuffer(wd, name_or_buf, len);
  474.     }
  475.     /*NOTREACHED*/
  476. }
  477.  
  478.  
  479. /*
  480.  * Display the help system. On the first call, create the help widget.
  481.  */
  482.  
  483. static void HelpCb(Widget w, XtPointer cd, XtPointer cb)
  484. {
  485.     static Widget helpDialog = NULL;
  486.  
  487.     if (helpDialog == NULL) {
  488.     char *title;
  489.     Arg args[10];
  490.     int n;
  491.  
  492.     n = 0;
  493.     XtSetArg(args[n], DtNhelpVolume, HelpVolume); n++;
  494.     XtSetArg(args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
  495.     XtSetArg(args[n], DtNlocationId, HelpTopic); n++;
  496.     helpDialog = DtCreateHelpDialog(appShell, "helpDialog", args, n);
  497.  
  498.     title = catgets(msgCatalog, 1, 4, "Template Help");
  499.     XtVaSetValues(XtParent(helpDialog), XmNtitle, title, NULL);
  500.     } else {
  501.     XtVaSetValues(helpDialog,
  502.               DtNhelpVolume, HelpVolume,
  503.               DtNlocationId, HelpTopic,
  504.               NULL);
  505.     }
  506.     XtManageChild(helpDialog);
  507. }
  508.  
  509.  
  510. /*
  511.  * Clear the display and drawing data.
  512.  */
  513.  
  514. static void ClearCb(Widget w, XtPointer cd, XtPointer cb)
  515. {
  516.     WindowData *wd = (WindowData *)cd;
  517.     Widget drawingArea = XtNameToWidget(wd->shell, "*drawingArea");
  518.  
  519.     FreeData(wd);
  520.     XClearWindow(XtDisplay(drawingArea), XtWindow(drawingArea));
  521. }
  522.  
  523.  
  524. /*
  525.  * Create a new top-level window.
  526.  */
  527. static void NewCb(Widget w, XtPointer cd, XtPointer cb)
  528. {
  529.     (void) NewWindow(LOAD_EMPTY, NULL, 0);
  530. }
  531.  
  532.  
  533. /*
  534.  * Display a File dialog. On the first call, create the dialog.
  535.  */
  536.  
  537. static void OpenCb(Widget w, XtPointer cd, XtPointer cb)
  538. {
  539.     WindowData *wd = (WindowData *)cd;
  540.  
  541.     if (wd->openDialog == NULL) {
  542.     XmString pattern;
  543.     XmString dialogTitle;
  544.     Arg args[20];
  545.     int n;
  546.  
  547.     dialogTitle = XmStringCreateLocalized(catgets(msgCatalog, 1, 2,
  548.                     "Template Open"));
  549.     pattern = XmStringCreateLocalized(SearchPattern);
  550.     n = 0;
  551.     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);n++;
  552.     XtSetArg(args[n], XmNautoUnmanage, True); n++;
  553.     XtSetArg(args[n], XmNpattern, pattern); n++;
  554.     XtSetArg(args[n], XmNdialogTitle, dialogTitle); n++;
  555.     wd->openDialog = XmCreateFileSelectionDialog(wd->shell, "openDialog",
  556.                              args, n);
  557.     XtUnmanageChild(XtNameToWidget(wd->openDialog, "*Help"));
  558.     XtAddCallback(wd->openDialog, XmNokCallback, OpenOkCb, cd);
  559.     XmStringFree(pattern);
  560.     XmStringFree(dialogTitle);
  561.     }
  562.     XtManageChild(wd->openDialog);
  563. }
  564.  
  565. static void OpenOkCb(Widget w, XtPointer cd, XtPointer cb)
  566. {
  567.     char *fileName;
  568.     WindowData *wd = (WindowData *)cd;
  569.     XmFileSelectionBoxCallbackStruct *fsbcs =
  570.     (XmFileSelectionBoxCallbackStruct *) cb;
  571.     Widget drawingArea = XtNameToWidget(wd->shell, "*drawingArea");
  572.  
  573.     XmStringGetLtoR(fsbcs->value, XmFONTLIST_DEFAULT_TAG, &fileName);
  574.     (void) LoadFile(wd, fileName);
  575.     XtFree(fileName);
  576.  
  577.     XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea), 0, 0, 0, 0, True);
  578. }
  579.  
  580.  
  581. /*
  582.  * Display a File dialog. On the first call, create the dialog.
  583.  */
  584.  
  585. static void SaveCb(Widget w, XtPointer cd, XtPointer cb)
  586. {
  587.     WindowData *wd = (WindowData *)cd;
  588.  
  589.     if (wd->saveDialog == NULL) {
  590.     XmString pattern;
  591.     XmString dialogTitle;
  592.     Arg args[20];
  593.     int n;
  594.  
  595.     dialogTitle = XmStringCreateLocalized(catgets(msgCatalog, 1, 3,
  596.                     "Template Save As"));
  597.     pattern = XmStringCreateLocalized(SearchPattern);
  598.     n = 0;
  599.     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);n++;
  600.     XtSetArg(args[n], XmNautoUnmanage, True); n++;
  601.     XtSetArg(args[n], XmNpattern, pattern); n++;
  602.     XtSetArg(args[n], XmNdialogTitle, dialogTitle); n++;
  603.     wd->saveDialog = XmCreateFileSelectionDialog(appShell, "saveAsDialog",
  604.                                 args, n);
  605.     XtUnmanageChild(XtNameToWidget(wd->saveDialog, "*Help"));
  606.     XtAddCallback(wd->saveDialog, XmNokCallback, SaveOkCb, cd);
  607.     XmStringFree(pattern);
  608.     XmStringFree(dialogTitle);
  609.     }
  610.  
  611.     XtManageChild(wd->saveDialog);
  612. }
  613.  
  614. static void SaveOkCb(Widget w, XtPointer cd, XtPointer cb)
  615. {
  616.     FILE *fp;
  617.     int i;
  618.     char * fileName;
  619.     int fileLength;
  620.     WindowData *wd = (WindowData *)cd;
  621.  
  622.     XmFileSelectionBoxCallbackStruct *fsbcs =
  623.     (XmFileSelectionBoxCallbackStruct *) cb;
  624.     XmStringGetLtoR(fsbcs->value, XmFONTLIST_DEFAULT_TAG, &fileName);
  625.     fileLength = strlen(fileName);
  626.  
  627.     if (fileName[fileLength-1]== '/') {
  628.     fileName = AppendString(fileName, UnnamedFile);
  629.     fileLength = strlen(fileName);
  630.     }
  631.  
  632.     if (fileLength > SuffixLength) {
  633.     if (strcmp(fileName+fileLength-SuffixLength, Suffix) != 0) {
  634.         fileName = AppendString(fileName,Suffix);
  635.     }
  636.     }
  637.     else {
  638.     fileName = AppendString(fileName, Suffix);
  639.     }
  640.  
  641.     if ((fp = fopen(fileName, "w")) != NULL) {
  642.     fputs(FileSignature, fp);
  643.     for (i=0; i < wd->npoints; i++)
  644.         fprintf(fp, "%d %d\n", wd->points[i].x, wd->points[i].y);
  645.     fclose(fp);
  646.     XtFree(wd->name);
  647.     wd->name = XtNewString(fileName);
  648.     SetTitle(wd->shell, fileName);
  649.     }
  650.  
  651.     XtFree(fileName);
  652. }
  653.  
  654. static char* AppendString(char *base, char *suffix)
  655. {
  656.     char *file;
  657.  
  658.     file = XtMalloc(strlen(base)+strlen(suffix)+1);
  659.     strcpy(file, base);
  660.     strcat(file, suffix);
  661.     XtFree(base);
  662.     return(file);
  663. }
  664.  
  665.  
  666. /*
  667.  * Respond to the TemplatePrint action by printing the data file
  668.  * specified to the '-print' option.
  669.  */
  670.  
  671. static void PrintCb(Widget w, XtPointer cd, XtPointer cb)
  672. {
  673.     WindowData *wd = (WindowData *)cd;
  674.     PrintData(wd);
  675. }
  676.  
  677.  
  678. /*
  679.  * Redraw the display when exposed.
  680.  */
  681.  
  682. static void ExposeCb(Widget w, XtPointer cd, XtPointer cb)
  683. {
  684.     XmDrawingAreaCallbackStruct *dcb = (XmDrawingAreaCallbackStruct*)cb;
  685.     WindowData *wd;
  686.     int i;
  687.  
  688.     if (dcb->event != NULL && dcb->event->xexpose.count > 0) return;
  689.  
  690.     wd = FindData(w);
  691.  
  692.     for (i = 0; i < wd->npoints; i++)
  693.     DrawPoint(w, wd->points[i].x, wd->points[i].y);
  694. }
  695.  
  696.  
  697. /*
  698.  * Process mouse input.
  699.  */
  700.  
  701. static void InputCb(Widget w, XtPointer cd, XtPointer cb)
  702. {
  703.     XmDrawingAreaCallbackStruct *dcb = (XmDrawingAreaCallbackStruct*)cb;
  704.     WindowData *wd;
  705.  
  706.     if (dcb->event->xany.type != ButtonPress &&
  707.     dcb->event->xany.type != MotionNotify)
  708.     return;
  709.  
  710.     wd = FindData(w);
  711.  
  712.     AddPoint(wd, dcb->event->xbutton.x, dcb->event->xbutton.y);
  713.     DrawPoint(w, dcb->event->xbutton.x, dcb->event->xbutton.y);
  714. }
  715.  
  716.  
  717. /*
  718.  * Delete the current window.  If there are no more windows, exit the 
  719.  * application.
  720.  */
  721.  
  722. static void ExitCb(Widget w, XtPointer cd, XtPointer cb)
  723. {
  724.     WindowData *wd = (WindowData *)cd;
  725.     DestroyData(wd);
  726.     if (windowList == NULL)
  727.     ReallyExit(0);
  728. }
  729.  
  730.  
  731. /*
  732.  * Handle WM_SAVE_YOURSELF by updating the command line with all the files
  733.  * currently being edited.
  734.  */
  735. static void SaveSessionCb(Widget w, XtPointer cd, XtPointer cb)
  736. {
  737.     char **command;
  738.     int argcount = 1;        /* starts at 1 for command name */
  739.     WindowData *wd = windowList;
  740.     int i;
  741.     Widget first;
  742.  
  743.     /* count the number of windows bound to files */
  744.     for (wd = windowList; wd != NULL; wd = wd->next) {
  745.     if (wd->name != NULL)
  746.         ++argcount;
  747.     }
  748.  
  749.     command = (char **)XtMalloc(argcount*sizeof(char*));
  750.     command[0] = argv0;
  751.     i = 1;
  752.     for (wd = windowList; wd != NULL; wd = wd->next) {
  753.     if (wd->name != NULL)
  754.         command[i++] = wd->name;
  755.     }
  756.  
  757.     first = windowList->shell;
  758.     XSetCommand(XtDisplay(first), XtWindow(first), command, i);
  759.     if (w != first)
  760.     XChangeProperty(XtDisplay(w), XtWindow(w), XA_WM_COMMAND, XA_STRING, 8,
  761.             PropModeReplace, NULL, 0);
  762.     XtFree((char *)command);
  763. }
  764.  
  765.  
  766. /*
  767.  * Accept .template files dropped on the drawing window.
  768.  */
  769.  
  770. static void DropTransferCb(Widget drawingArea, XtPointer cd, XtPointer cb)
  771. {
  772.     DtDndTransferCallbackStruct *dcb = (DtDndTransferCallbackStruct*)cb;
  773.     WindowData *wd = FindData(drawingArea);
  774.     char *fileName;
  775.     char *dataType;
  776.     void *bufPtr;
  777.     int bufLen;
  778.  
  779.     dcb->status = DtDND_FAILURE;
  780.  
  781.     if (dcb->dropData->numItems > 1)
  782.     return;
  783.  
  784.     switch (dcb->dropData->protocol) {
  785.  
  786.     case DtDND_FILENAME_TRANSFER:
  787.      fileName = dcb->dropData->data.files[0];
  788.     dataType = DtDtsFileToDataType(fileName);
  789.         if (strcmp(dataType, DataType) != 0) {
  790.         DtDtsFreeDataType(dataType);
  791.         return;
  792.         }
  793.         if (LoadFile(wd, fileName))
  794.             dcb->status = DtDND_SUCCESS;
  795.     DtDtsFreeDataType(dataType);
  796.     break;
  797.  
  798.     case DtDND_BUFFER_TRANSFER:
  799.     bufPtr   = dcb->dropData->data.buffers[0].bp;
  800.     bufLen   = dcb->dropData->data.buffers[0].size;
  801.     dataType = DtDtsBufferToDataType(bufPtr, bufLen, NULL);
  802.     if (strcmp(dataType, DataType) != 0) {
  803.         DtDtsFreeDataType(dataType);
  804.         return;
  805.     }
  806.     if (LoadBuffer(wd, bufPtr, bufLen))
  807.             dcb->status = DtDND_SUCCESS;
  808.     DtDtsFreeDataType(dataType);
  809.     break;
  810.     }
  811.  
  812.     XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea),
  813.     0, 0, 0, 0, True);
  814. }
  815.  
  816.  
  817. /*
  818.  * Set the widget's title to the program name followed by a separator followed
  819.  * by the trailing pathname component of the filename.  The widget must be a
  820.  * shell.  If name is NULL, uses "(untitled)" instead.
  821.  */
  822. static void
  823. SetTitle(Widget w, char *name)
  824. {
  825.     char buf[1000];
  826.     char *p;
  827.  
  828.     if (name == NULL) {
  829.     p = untitledString;
  830.     } else {
  831.     p = strrchr(name, '/');
  832.     if (p == NULL)
  833.         p = name;
  834.     else
  835.         p++;
  836.     }
  837.     sprintf(buf, "%s%s%s", appnameString, separatorString, p);
  838.     XtVaSetValues(w, XtNtitle, buf, NULL);
  839. }
  840.  
  841.  
  842. /*
  843.  * Create a new WindowData structure.  The widget passed in should be the 
  844.  * shell associated with this data.  It must be realized.
  845.  */
  846. static WindowData *
  847. NewData(void)
  848. {
  849.     WindowData *wd;
  850.  
  851.     wd = XtNew(WindowData);
  852.     wd->npoints = 0;
  853.     wd->nalloc = 0;
  854.     wd->points = NULL;
  855.     wd->shell = NULL;
  856.     wd->openDialog = NULL;
  857.     wd->saveDialog = NULL;
  858.     wd->name = NULL;
  859.  
  860.     /* push it onto the front of the global list */
  861.     wd->next = windowList;
  862.     windowList = wd;
  863.  
  864.     return wd;
  865. }
  866.  
  867.  
  868. /*
  869.  * Associate a top-level shell with a WindowData structure.  The shell must be 
  870.  * realized.
  871.  */
  872. static void
  873. AssocData(WindowData *wd, Widget w)
  874. {
  875.     wd->shell = w;
  876.     XSaveContext(XtDisplay(w), XtWindow(w), wdContext, (XPointer)wd);
  877. }
  878.  
  879.  
  880. /*
  881.  * Given a widget, find the WindowData structure associated with it.  First it 
  882.  * finds the shell ancestor of this widget, and then it extracts the window 
  883.  * data from using the X Context Manager.
  884.  */
  885. static WindowData *
  886. FindData(Widget w)
  887. {
  888.     WindowData *wd = NULL;
  889.  
  890.     while (! XtIsShell(w))
  891.     w = XtParent(w);
  892.     XFindContext(XtDisplay(w), XtWindow(w), wdContext, &wd);
  893.     return wd;
  894. }
  895.  
  896.  
  897. /*
  898.  * Destroy a WindowData structure.
  899.  */
  900. static void
  901. DestroyData(WindowData *wd)
  902. {
  903.     WindowData **p;
  904.  
  905.     FreeData(wd);
  906.  
  907.     if (wd->shell != NULL)
  908.     XtDestroyWidget(wd->shell);
  909.     if (wd->openDialog != NULL)
  910.     XtDestroyWidget(wd->openDialog);
  911.     if (wd->saveDialog != NULL)
  912.     XtDestroyWidget(wd->saveDialog);
  913.  
  914.     /* remove from the global list */
  915.  
  916.     p = &windowList;
  917.     while (*p != NULL) {
  918.     if (*p == wd) {
  919.         *p = wd->next;
  920.         break;
  921.     }
  922.     p = &((*p)->next);
  923.     }
  924.  
  925.     XtFree((char *)wd);
  926. }
  927.  
  928. /*
  929.  * Load a .template data file
  930.  */
  931.  
  932. static Boolean LoadFile(WindowData *wd, char *fileName)
  933. {
  934.     FILE *fp;
  935.     int np, i, x, y;
  936.     char sig[100];
  937.  
  938.     if ((fp = fopen(fileName, "r")) == NULL)
  939.     return False;
  940.  
  941.     if (fgets(sig, sizeof(sig), fp) == NULL) {
  942.     fclose(fp);
  943.     return False;
  944.     }
  945.  
  946.     if (strcmp(sig, FileSignature) != 0) {
  947.     fclose(fp);
  948.     return False;
  949.     }
  950.  
  951.     FreeData(wd);
  952.     while (fscanf(fp, "%d %d", &x, &y) != EOF)
  953.     AddPoint(wd, x, y);
  954.     fclose(fp);
  955.     if (wd->shell != NULL)
  956.     SetTitle(wd->shell, fileName);
  957.     wd->name = XtNewString(fileName);
  958.     return True;
  959. }
  960.  
  961.  
  962. /*
  963.  * Load a .template buffer
  964.  */
  965.  
  966. static Boolean LoadBuffer(WindowData *wd, void *buf, int len)
  967. {
  968.     char *bufp = (char *)buf;
  969.     char *endp = bufp + len;
  970.     int r, x, y, l;
  971.     char sig[100];
  972.  
  973.     (void) strncpy(sig, bufp, sizeof(FileSignature) - 1);
  974.     sig[sizeof(FileSignature) - 1] = '\0';
  975.     if (strcmp(sig, FileSignature) != 0)
  976.     return False;
  977.     bufp += sizeof(FileSignature) - 1;
  978.  
  979.     FreeData(wd);
  980.     while (bufp < endp) {
  981.     if (sscanf(bufp, "%d %d\n%n", &x, &y, &l) != 2)
  982.         return False;
  983.     AddPoint(wd, x, y);
  984.     bufp += l;
  985.     }
  986.     if (wd->shell != NULL)
  987.     SetTitle(wd->shell, NULL);
  988.     return True;
  989. }
  990.  
  991.  
  992. static Tt_message
  993. HandleTtMedia(
  994.     Tt_message        msg,
  995.     void        *clientdata,
  996.     Tttk_op        op,
  997.     Tt_status        diagnosis,
  998.     unsigned char    *contents,
  999.     int            len,
  1000.     char        *file,
  1001.     char        *docname)
  1002. {
  1003.     int mark = tt_mark();
  1004.     char *opstr = tt_message_op(msg);
  1005.  
  1006.     if (strcmp(opstr, "Edit") == 0) {
  1007.     if (file != NULL) {
  1008.         if (NewWindow(LOAD_FILE, file, 0))
  1009.         tt_message_reply(msg);
  1010.         else
  1011.         tttk_message_fail(msg, TT_ERR_OP, "open failed", False);
  1012.     } else if (contents != NULL && len > 0) {
  1013.         if (NewWindow(LOAD_BUFFER, (char *)contents, len))
  1014.         tt_message_reply(msg);
  1015.         else
  1016.         tttk_message_fail(msg, TT_ERR_OP, "load buffer failed", False);
  1017.     } else {
  1018.         tttk_message_fail(msg, TT_ERR_OP, "no file or buffer", False);
  1019.     }
  1020.     } else {
  1021.     tttk_message_fail(msg, TT_ERR_OP, "unsupported message", False);
  1022.     }
  1023.  
  1024.     tt_release(mark);
  1025.     tt_free((char *)contents);
  1026.     tt_free(file);
  1027.     tt_free(docname);
  1028.     tt_message_destroy(msg);
  1029.     return 0;
  1030. }
  1031.  
  1032.  
  1033. /*
  1034.  * Print the drawing data.
  1035.  *
  1036.  * This function is intentionally left blank.
  1037.  */
  1038.  
  1039. static void PrintData(WindowData *wd)
  1040. {
  1041.     FILE *PS;
  1042.     int i;
  1043.  
  1044.     PS = popen("/usr/bin/lp", "w");
  1045.  
  1046.     fputs("%!\n", PS);
  1047.     fputs("clippath pathbbox 0 exch translate pop pop pop\n", PS);
  1048.     fputs("1 -1 scale 72 72 translate\n", PS);
  1049.     fputs("newpath 0.5 setgray\n", PS);
  1050.     fputs("/S { 10 0 360 arc fill } def\n", PS);
  1051.  
  1052.     for (i = 0; i < wd->npoints; i++)
  1053.     fprintf(PS, "%d %d S\n", wd->points[i].x, wd->points[i].y);
  1054.  
  1055.     fputs("showpage\n", PS);
  1056.     (void) pclose(PS);
  1057. }
  1058.  
  1059.  
  1060. /*
  1061.  * Free drawing data structure
  1062.  */
  1063.  
  1064. static void FreeData(WindowData *wd)
  1065. {
  1066.     XtFree((char *)wd->points);
  1067.     XtFree(wd->name);
  1068.     wd->points = NULL;
  1069.     wd->name = NULL;
  1070.     wd->npoints = 0;
  1071.     wd->nalloc = 0;
  1072.     if (wd->shell != NULL)
  1073.     SetTitle(wd->shell, NULL);
  1074. }
  1075.  
  1076.  
  1077. /*
  1078.  * Add a point to the end of the drawing data structure.
  1079.  */
  1080.  
  1081. static void AddPoint(WindowData *wd, int x, int y)
  1082. {
  1083.     if (wd->npoints == wd->nalloc) {
  1084.     wd->nalloc += MallocInc;
  1085.     wd->points =
  1086.         (XPoint*)XtRealloc((char*)wd->points, wd->nalloc * sizeof(XPoint));
  1087.     }
  1088.     wd->points[wd->npoints].x = x;
  1089.     wd->points[wd->npoints].y = y;
  1090.     wd->npoints += 1;
  1091. }
  1092.  
  1093.  
  1094. /*
  1095.  * Draw an airbrush at (x,y)
  1096.  */
  1097.  
  1098. static void DrawPoint(Widget w, int x, int y)
  1099. {
  1100.     static Boolean initialized = False;
  1101.     static GC gc;
  1102.     static Pixmap pixmap;
  1103.     static unsigned int pixmapWidth, pixmapHeight;
  1104.  
  1105.     if (XtIsRealized(w) == False) return;
  1106.  
  1107.     if (initialized == False) {
  1108.     Pixel fg, bg;
  1109.     unsigned int tmpu;
  1110.     Window tmpw;
  1111.     int tmpi;
  1112.     XGCValues gcv;
  1113.     unsigned long gcm;
  1114.  
  1115.     XtVaGetValues(w, XmNforeground, &fg, XmNbackground, &bg, NULL);
  1116.     pixmap = XmGetPixmapByDepth(XtScreen(w), "template-brush.bm", 1, 0, 1);
  1117.     if (pixmap == XmUNSPECIFIED_PIXMAP) {
  1118.         XtAppWarning(appContext, "template:template-brush.bm not installed!");
  1119.         /* use hardcoded fallback bitmap */
  1120.         pixmap = XCreatePixmapFromBitmapData(XtDisplay(w), XtWindow(w),
  1121.                 (char*)default_brush_bits,
  1122.                 default_brush_width,
  1123.                 default_brush_height,
  1124.                 1, 0, 1);
  1125.     }
  1126.     XGetGeometry(XtDisplay(w), pixmap, &tmpw, &tmpi, &tmpi,
  1127.             &pixmapWidth, &pixmapHeight, &tmpu, &tmpu);
  1128.  
  1129.     gcm = GCForeground | GCBackground | GCFillStyle | GCStipple;
  1130.     gcv.foreground = fg;
  1131.     gcv.background = bg;
  1132.     gcv.fill_style = FillStippled;
  1133.     gcv.stipple = pixmap;
  1134.     gc = XCreateGC(XtDisplay(w), XtWindow(w), gcm, &gcv);
  1135.  
  1136.     initialized = True;
  1137.     };
  1138.  
  1139.     XSetTSOrigin(XtDisplay(w), gc, x-pixmapWidth/2, y-pixmapWidth/2);
  1140.     XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1141.             x-pixmapWidth/2, y-pixmapWidth/2,
  1142.             pixmapWidth, pixmapHeight);
  1143. }
  1144.  
  1145.